package han.cirno.corrupt.data

import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverter
import androidx.room.TypeConverters
import com.google.gson.Gson
import han.cirno.corrupt.Application
import han.cirno.corrupt.data.instances.ClassEntryDao
import han.cirno.corrupt.data.instances.ClassTableDao
import han.cirno.corrupt.data.instances.DateInfoDao
import han.cirno.corrupt.data.instances.ExamDao
import han.cirno.corrupt.data.instances.ScoreDao
import han.cirno.corrupt.data.instances.TaskDataDao
import han.cirno.corrupt.data.instances.TaskTagDao
import han.cirno.corrupt.data.instances.UserClassesData
import han.cirno.corrupt.data.instances.UserClassesData.DayOfWeek
import han.cirno.corrupt.data.instances.UserClassesData.TimeRange
import han.cirno.corrupt.data.instances.UserExamData
import han.cirno.corrupt.data.instances.UserScoreData
import han.cirno.corrupt.data.instances.UserTaskData
import java.util.Date

@Suppress("UNCHECKED_CAST")
@TypeConverters(DB.Converters::class)
@Database(
    entities=[
        UserClassesData.DateInfo::class,
        UserClassesData.ClassTable::class,
        UserClassesData.ClassEntry::class,
        UserExamData.Exam::class,
        UserScoreData.Score::class,
        UserTaskData.TaskData::class,
        UserTaskData.TaskTag::class],
    version=5,exportSchema=false
)
abstract class DB:RoomDatabase() {
    abstract fun dateInfoDao():DateInfoDao
    abstract fun classEntryDao():ClassEntryDao
    abstract fun classTableDao():ClassTableDao
    abstract fun examDao():ExamDao
    abstract fun scoreDao(): ScoreDao
    abstract fun taskTagDao():TaskTagDao
    abstract fun taskDataDao():TaskDataDao

    companion object {
        @Volatile
        private var instance:DB?=null
        fun getInstance():DB {
            return instance ?: synchronized(this) {
                val instance1=Room.databaseBuilder(
                    Application.application,
                    DB::class.java,
                    "db.db"
                ).fallbackToDestructiveMigration().build()
                instance1.also {instance=it}
            }
        }
    }
    @Suppress("unused")
    object Converters {
        private val gson=Gson()
        @TypeConverter
        fun converterDayOfWeek(dayOfWeek:DayOfWeek):String=dayOfWeek.name
        @TypeConverter
        fun revertDayOfWeek(name:String):DayOfWeek=DayOfWeek.valueOf(name)
        @TypeConverter
        fun converterIntArray(intArray:IntArray):String=gson.toJson(intArray)
        @TypeConverter
        fun revertIntArray(array:String):IntArray=gson.fromJson(array,IntArray::class.java)
        @TypeConverter
        fun converterTimeRange(timeRange:TimeRange):String=gson.toJson(timeRange)
        @TypeConverter
        fun revertTimeRange(range:String):TimeRange=gson.fromJson(range,TimeRange::class.java)
        @TypeConverter
        fun converterTriple(triple:Triple<String,String,String>):String=gson.toJson(triple)
        @TypeConverter
        fun revertTriple(s:String):Triple<String,String,String> =gson.fromJson(s,Triple::class.java) as Triple<String,String,String>
        @TypeConverter
        fun converterPair(pair:Pair<String,String>):String=gson.toJson(pair)
        @TypeConverter
        fun revertPair(s:String):Pair<String,String> =gson.fromJson(s,Pair::class.java) as Pair<String,String>
        @TypeConverter
        fun converterDate(date:Date):String=gson.toJson(date)
        @TypeConverter
        fun revertDate(s:String):Date=gson.fromJson(s,Date::class.java)
        @TypeConverter
        fun converterArrayList(list:MutableList<Long>):String=gson.toJson(list)
        @TypeConverter
        fun revertArrayList(s:String):MutableList<Long> =gson.fromJson(s,MutableList::class.java) as MutableList<Long>
    }
}